/***************************************************************************************
* Copyright (c) 2014-2024 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*          http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include <string.h>

#define CHECK_BUF_SIZE(size_needed) \
  if(index_buf +(size_needed) >= sizeof(buf)) { \
    printf("Buffer overflow prevented\n"); \
    return; \
  }
// this should be enough
static char buf[65536] = {};
static char code_buf[65536 + 128] = {}; // a little larger than `buf`
static char *code_format =
"#include <stdio.h>\n"
"#include <stdint.h>\n"
"int main() { "
"  uint32_t result = %s; "
"  printf(\"%%u\", result); "
"  return 0; "
"}";
int index_buf = 0;
int max_depth = 5;
int choose(int n){
  int flag = rand()%n;
  //printf("index = %d,flag = %d. \n",index_buf,flag);
  return flag;
}
void gen_num(){
  int num = rand()%100;
  int len = snprintf(&buf[index_buf],sizeof(buf)-index_buf,"%d",num);//可以指定写入的最大还春去大小，
  if(len < 0||len >= sizeof(buf) -index_buf){
    printf("Buffer overflow in gen_num \n");
  }
  index_buf += len;

}
void gen (char c){
  CHECK_BUF_SIZE(1);
  buf[index_buf ++] = c;
}

void gen_rand_op(){
  char op[4] = { '+', '-','*','/'};
  int op_position = rand()%4;
  CHECK_BUF_SIZE(1);
  buf[index_buf ++] = op[op_position];
}

static void gen_rand_expr(int depth) {
  // buf[0] = '\0';
  if(index_buf > 65530) {
    printf("overSize \n");
    return;
  }
  if(depth > max_depth){
    gen_num();
    return ;
  }
  switch (choose(3)){
    case 0:
      gen_num();
      break;
    case 1:
      gen('(');
      gen_rand_expr(depth+1);
      gen(')');
      break;
    default:
      gen_rand_expr(depth+1);
      gen_rand_op();
      gen_rand_expr(depth+1);
      break;
  }
}

int main(int argc, char *argv[]) {
  int seed = time(0);
  srand(seed);
  int loop = 1;
  if (argc > 1) {
    //读取命令行参数，作为循环次数
    sscanf(argv[1], "%d", &loop);
  }

  int i;
  for (i = 0; i < loop; i ++) {
    index_buf = 0;
    memset(buf,0,sizeof(buf));
    gen_rand_expr(0);

    sprintf(code_buf, code_format, buf);

    FILE *fp = fopen("/tmp/.code.c", "w");
    assert(fp != NULL);
    fputs(code_buf, fp);
    fclose(fp);

    int ret = system("gcc /tmp/.code.c -Wall -Werror -o /tmp/.expr");
    if (ret != 0) 
    {
      printf("Compilation failed, skipping this expression.\n");
      continue;
    }

    fp = popen("/tmp/.expr", "r");
    assert(fp != NULL);

    unsigned long result;
    ret = fscanf(fp, "%lu", &result);
    pclose(fp);
    printf("%lu %s\n", result, buf);
    //system("rm /tmp/.code /tmp/.expr");

  }
  return 0;
}
 
